
#include <string>
#include <vector>
#include <iostream>
#include "torrenting.hpp"

#include <ncurses.h>

void draw_topbar(const WINDOW * const w, const int &MAX_X, std::string s) {
    for (unsigned int i= 0; i < MAX_X; i++) {
        s.push_back(' ');
    }
    attron(A_BOLD);
    attron(COLOR_PAIR(1));
    mvwprintw(stdscr, 0, 0, s.c_str());
    attroff(COLOR_PAIR(1));
    attroff(A_BOLD);
}

class TuiCell {
    public:
        // x and y position is controlled by TuiRows
        int pos_x;
        int pos_y;
        std::string text;

        TuiCell();
        TuiCell(std::string s) {
            this -> text = s;
            this -> pos_x =0;
            this -> pos_y =0 ;
        }
};

class TuiRows {
    private:
        TuiCell * top_row;
//         std::vector<TuiCell*> rows;
    public:
        WINDOW *w;
        int columns; // number of cells
        int *places = NULL;

        // for draw_blank_row()
        int max_x;
        int max_y;
        char *blank = NULL;

        // first row (label) determines the x positions of later rows
        TuiRows(WINDOW *win, TuiCell * const first_row, int num) {
            this -> w = win;
            this -> places = new int[num];
            if (this -> places == NULL) {
                std::cerr << "error: failed to allocate memory"<< std::endl;
            }
            int curr_x = 0;
            for (unsigned int i = 0; i < num; i++) {
                first_row[i].pos_x = curr_x;
                this -> places[i] = curr_x;
                curr_x += first_row[i].text.length() + 8;
            }
            this -> top_row = first_row;
//             this -> rows.push_back(first_row);
            this -> columns = num;

            getmaxyx(this -> w, this -> max_y, this -> max_x);
            std::cerr << "max_x is" << this -> max_x << std::endl;
            if (this -> max_x != 0) {
                this -> blank = new char[this -> max_x];
            }
            if (this -> blank != NULL) {
                unsigned int last = (this -> max_x) - 1;
                for (unsigned int i = 0; i < last; i++) {
                    blank[i] = ' ';
                }
                blank[last] = '\0';
            }
        }

        ~TuiRows() {
            delete [] this -> places;
            delete [] this -> blank;
        }

        void draw_row (TuiCell * row, int num, int y_offset = 0) const {
            for (unsigned int i = 0; i < num; i++) {
                TuiCell c = row[i];
                int y = c.pos_y + y_offset;
                mvwprintw(this -> w, y, places[i], "%-4s", c.text.c_str());
            }
        }

        // needed so the entire line has an attribute set
        void draw_blank_row(int y) const {
            mvwprintw(this -> w, y, 0, this -> blank);
        }

        void draw (int y_offset=0) const {
            this -> draw_row(this -> top_row, this -> columns, y_offset);
        }
};

void draw_stats (TuiRows &tuir, 
                 std::vector<lt::torrent_handle> &h, 
                 int highlight) {
    int y = 1;
    for (unsigned int i = 0; i < h.size(); i++) {
        lt::torrent_status ts = h[i].status();
        std::string name = ts.name.substr(0,10);
        float down = (float)ts.download_rate/1000000.0;
        float up   = (float)ts.upload_rate/1000000.0;
        std::string peers;
        {
            std::stringstream ss;
            ss << ts.num_peers << "(" << ts.list_peers<<  ")";
            peers = ss.str();
        }
        std::string seeds;
        {
            std::stringstream ss;
            ss << ts.num_seeds << "(" << ts.list_seeds<<  ")";
            seeds = ss.str();
        }
        TuiCell c[] = {
            TuiCell(peers), 
            TuiCell(seeds),
            TuiCell(std::to_string(up)),
            TuiCell(std::to_string(down)),
            TuiCell(name)
        };
        if (i == highlight) {
            attron(A_STANDOUT);
        }
        tuir.draw_blank_row(y);
        tuir.draw_row(c,5,y);
        if (i == highlight) {
            attroff(A_STANDOUT);
        }
        y++;
    }
    tuir.draw();
}

void test(std::string &placeholder) {
    initscr();
    if (has_colors() == FALSE) {
        endwin();
        fprintf(stderr, "Error: terminal does not support colors");
        return;
    }
    start_color();			/* Start color 			*/
	init_pair(1, COLOR_WHITE, COLOR_BLUE);
    raw();
    keypad(stdscr, TRUE);
    noecho();
    timeout(10);

    int max_x, max_y;
    getmaxyx(stdscr, max_y, max_x);

//     draw_topbar(stdscr, max_x, " cppia (unrealeased) - press 'q' to quit");

    TuiCell f[] = {
        TuiCell("PEERS"), 
        TuiCell("SEEDS"),
        TuiCell("UPLOAD (MB/s)"),
        TuiCell("DOWNLOAD (MB)/s"),
        TuiCell("NAME")
    };
    TuiRows label(stdscr, f, 5);
//     label.draw(0);

    lt::session s;
    std::vector<std::string> paths = readfile(placeholder.c_str());
    if (paths.empty()) {
        return;
    }
    init_torrents(s, paths);
    std::vector<lt::torrent_handle> handles = s.get_torrents();
    int TOTAL_TORRENTS = handles.size();

    int ch = 0; 
    unsigned int last = TOTAL_TORRENTS - 1; //+ Y_START - 1;
    unsigned int highlight = 0;
    while (true) { // 27 = ESC 
        draw_stats(label, handles, highlight);
        ch = getch();
        switch (ch) {
            case KEY_UP:
                if (highlight > 0) {
                    highlight--;
                } else {
                    highlight = last;
                } 
                break;
            case KEY_DOWN:
                if (highlight < last) {
                    highlight++;
                } else {
                    highlight = 0;
                }
                break;
            case 27:
            case 'q':
                goto stop;
                break;
        }
    }
    stop:
    endwin();
}


int main(int argc, char const* argv[]) {
    std::cout << "This is cppia (unreleased)." << std::endl;
    bool success;
    switch (argc) {
        case 1: 
            std::cout << "Usages: \n"
              << "\t cppia <video url>\n"
              << "\t cppia seed <list of torrent files>" << std::endl;
            break;
        case 2: 
            // if there is only one argument, assume it is a video url
             success = watch(std::string(argv[1]));
            if (!success) {
                std::cout << "Usage: cppia <video url>" << std::endl;
            }
            break;
        case 3:
            std::string option (argv[1]);
            std::string s(argv[2]);
            if (option.compare("seed") == 0) {
                seedbox(s);
            } else if (option.compare("test") == 0) {
                test(s);
            }
            break;
    }
    return 0;
}
